/*
 * TMesh.h
 *
 *  Created on: 12/09/2012
 *      Author: rogsoares
 */

#ifndef TMESH_H_
#define TMESH_H_

#include "Matrix.h"

struct VertexData{
	int numRC;
	int ID;
	int ID_PETScOrdering;
	int ID_local;			// for visualization purposes only
	int flag;
	double x;
	double y;
	double z;

	double volume;
	double weighted_volume;
	double nonvisc;
	double *grad_p;
	double *grad_Sw;
	double *vel;			// for visualization purposes only
	int countedges;			// for visualization purposes only
	double p;
	double Sw;
	double lambda_total;
	bool hasWell;
};

struct VertexWell{
	int ID;
	VertexData* vertex;
	double Qi;					// fractional fluid flow through well
};

struct EdgeData{
	double *Cij;
	double Cij_norm;
	double length;
	double *versor;
	double aux_Matrix_G;
	double *aux_Matrix_E;

	double *vel_new;
	double *vel_old;
	int numRC;
	int ID_0;
	int ID_1;
	int flag;
	VertexData* vertex_0;
	VertexData* vertex_1;
};

struct BdryElementData{
	double *Dij;
	double* versor;
	int numRC;
	int ID_0;
	int ID_1;
	int ID_2;
	int flag;
	VertexData* vertex_0;
	VertexData* vertex_1;
	VertexData* vertex_2;
	int dom1;
	int dom2;
};


class TMesh{
public:

	TMesh(){}
	~TMesh(){}

	void createMesh(int ndom, const int *numNodesPerDomain, const int *numBdryNodesPerDomain, const int *numEdgesPerDomain, const int *numBDryEdgesPerDomain);

	/*
	 * Matrix m x n. Each matrix column is a specific production well.
	 *
	 *  well_1   well_2  ...   well_n
	 * node_11  node_12  ...  node_1n
	 * node_21  node_22  ...  node_2n
	 *   ...
	 * node_m1  node_m2  ...  node_mn
	 *
	 * Of course, the number of nodes for each well may be different. The number of rows of matrix 'well_vertices_list' will be the maximum number
	 * of nodes for well j.
	 *
	 */
	Matrix<VertexData*> *vertices_list;			// vector of 1 column matrix. Each vector index is a 1 columns matrix with all domain vertices
	Matrix<VertexData*> *bdry_vertices_list;	// vector of 1 column matrix. Each vector index is a 1 columns matrix with all domain vertices
	Matrix<EdgeData*> *edge_list;				// vector of 1 column matrix. Each vector index is a 2 columns matrix with all domain edges
	Matrix<BdryElementData*> *bdry_elem_list;		// vector of 1 column matrix. Each vector index is a 2 columns matrix with all domain edges

	Matrix<VertexData*> dirichlet_list;			// array of all nodes with prescribed values
	Matrix<VertexWell*> *productionWells_list;	// array of arrays. Each array contains all vertices for a specific production well.
	Matrix<VertexWell*> *injectionWells_list;	// array containing all vertices for a specific injection well. (Neumamm condition)
	Matrix<VertexData*> vertices_WithOutWells;	// An array of vertices not flagged for well (injection or production)
	Matrix<VertexData*> allVertices;
	Matrix<VertexData*> allEdges;


	void setNumDomains(int d){
		ndom = d;
	}

	int getNumDomains() const{
		return ndom;
	}

	void setMeshDim(int d){
		dim = d;
	}

	int getMeshDim() const{
		return dim;
	}

	void set_data_lists(){
		vertices_list = new Matrix<VertexData*>[ndom];
		bdry_vertices_list = new Matrix<VertexData*>[ndom];
		edge_list = new Matrix<EdgeData*>[ndom];
		bdry_elem_list = new Matrix<BdryElementData*>[ndom];
		domFlags = new int[ndom];
	}

	void setdomFlags(int i, int flag){
		domFlags[i] = flag;
	}

	int getdomFlags(int i){
		return domFlags[i];
	}

	void mapDomainsFlags(){
		for (int i=0; i<ndom; i++){
			int flag = domFlags[i];
			mdf[flag] = i;
		}
	}

	int getMappedIndexFromFlag(int flag){
		return mdf[flag];
	}

	void setNumGEdges(int ne){
		numglobaledges = ne;
	}

	int getNumGEdges() const{
		return numglobaledges;
	}

	double getMaximumEdgeLentgh()const{
		return maxEdgeLength;
	}

	void setMaximumEdgeLentgh(double maxe){
		maxEdgeLength = maxe;
	}

	int getNumGVertices() const{
		return numglobalvertices;
	}

	void setNumGVertices(int ne){
		numglobalvertices = ne;
	}

	int getNumInjectionWells() const{
		return numinjectionwells;
	}

	void setNumInjectionWells(int ne){
		numinjectionwells = ne;
		pInjectionWellFlags = new int[ne];
	}

	int getNumProductionWells() const{
		return numproductionwells;
	}

	void setNumProductionWells(int ne){
		numproductionwells = ne;
		pProductionWellFlags = new int[ne];
	}

	int getProductionWellFlag(int i) const{
		return pProductionWellFlags[i];
	}

	void setProductionWellFlag(int i, int flag){
		pProductionWellFlags[i] = flag;
	}

	int getInjectionWellFlag(int i) const{
		return pInjectionWellFlags[i];
	}

	void setInjectionWellFlag(int i, int flag){
		pInjectionWellFlags[i] = flag;
	}

	int getNumLocalEdges() const{
		return numLocalEdges;
	}

	void setNumLocalEdges(int nedges){
		numLocalEdges = nedges;
	}

private:

	int dim;
	int ndom;
	int *domFlags;
	std::map<int,int> mdf;
	int numglobaledges;
	int numglobalvertices;
	int numinjectionwells;
	int numproductionwells;
	int* pInjectionWellFlags;
	int* pProductionWellFlags;
	int numLocalEdges;
	double maxEdgeLength;
};

#endif /* TMESH_H_ */
